#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <sys/time.h>
#include <sys/stat.h>

#include <psp2/kernel/clib.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_mixer.h>
#include <SDL2/SDL_ttf.h>

#include "utils.h"
#include "main.h"

void *__wrap_memcpy(void *dest, const void *src, size_t n)
{
	return sceClibMemcpy(dest, src, n);
}

void *__wrap_memmove(void *dest, const void *src, size_t n)
{
	return sceClibMemmove(dest, src, n);
}

void *__wrap_memset(void *s, int c, size_t n)
{
	return sceClibMemset(s, c, n);
}

struct tm *localtime_soloader(time_t *timer)
{
	struct tm *res = localtime(timer);
	if (res)
		return res;
	// Fix an uninitialized variable bug.
	time(timer);
	return localtime(timer);
}

FILE *fopen_soloader(const char *filename, const char *mode)
{
	debugPrintf("fopen: %s -%s ...\n", filename, mode);

	FILE *res = fopen(filename, mode);

	if (res == NULL)
		debugPrintf("fopen: failed\n");
	else
		debugPrintf("fopen: done\n");

	return res;
}

int __android_log_vprint(int prio, const char *tag, const char *fmt, ...)
{
#ifdef DEBUG
	va_list list;
	char string[4096];

	va_start(list, fmt);
	vsprintf(string, fmt, list);
	va_end(list);

	debugPrintf("%s: %s\n", tag, string);
#endif
	return 0;
}

int __android_log_print(int prio, const char *tag, const char *fmt, ...)
{
#ifdef DEBUG
	va_list list;
	char string[4096];

	va_start(list, fmt);
	vsprintf(string, fmt, list);
	va_end(list);

	debugPrintf("%s: %s\n", tag, string);
#endif
	return 0;
}

int SDL_Android_Init_soloader()
{
	debugPrintf("SDL_Android_Init called\n");

	return 0;
}

int SDL_AudioInit_soloader(const char *driver_name)
{
	debugPrintf("SDL_AudioInit called: %s\n", driver_name);
	int ret = SDL_AudioInit(driver_name);

	return ret;
}

int SDL_VideoInit_soloader(const char *driver_name)
{
	debugPrintf("SDL_VideoInit called: %s\n", driver_name);
	int ret = SDL_VideoInit(driver_name);

	return ret;
}

SDL_Window *SDL_CreateWindow_soloader(const char *title, int x, int y, int w, int h, Uint32 flags)
{
	debugPrintf("SDL_CreateWindow: title: %s, x:%d, y:%d, w:%d, h:%d, flags:%u\n", title, x, y, w, h, flags);
	SDL_Window *window = SDL_CreateWindow(title, x, y, w, h, flags);
	if (!window)
		debugPrintf("SDL_CreateWindow: failed\n");
	else
		debugPrintf("SDL_CreateWindow: 0x%X done\n", window);

	return window;
}

int SDL_SetWindowDisplayMode_soloader(SDL_Window *window, const SDL_DisplayMode *mode)
{
	debugPrintf("SDL_SetWindowDisplayMode: 0x%X, mode:%d\n", window, mode);
	return SDL_SetWindowDisplayMode(window, mode);
}

void SDL_ShowWindow_soloader(SDL_Window *window)
{
	debugPrintf("SDL_ShowWindow: 0x%X\n", window);
	SDL_ShowWindow(window);
}

SDL_Renderer *SDL_CreateRenderer_soloader(SDL_Window *window, int index, Uint32 flags)
{
	debugPrintf("SDL_CreateRenderer: window: 0x%X, index: %d, flags: %u\n", window, index, flags);
	SDL_Renderer *renderer = SDL_CreateRenderer(window, index, flags);
	if (!renderer)
		debugPrintf("SDL_CreateRenderer: failed\n");
	else
		debugPrintf("SDL_CreateRenderer: 0x%X done\n", renderer);

	return renderer;
}

void SDL_RenderPresent_soloader(SDL_Renderer *renderer)
{
	SDL_RenderPresent(renderer);
}

int GetAndroidFileIsExists(const char *path)
{
	return file_exists(path);
}

void patch_game()
{
	hook_addr(so_symbol(&so_mod, "_Z22GetAndroidFileIsExistsPKc"), (uintptr_t)&GetAndroidFileIsExists);
}
